package com.nf.teamwork.mall.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nf.teamwork.mall.entity.UserInf;
import com.nf.teamwork.mall.utils.JwtUtil;
import com.nf.teamwork.mall.utils.RsaKeyProperties;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: LJP
 * @Classname JwtLoginFilter
 * @Date: 2020-02-29 19:14
 * @Description: 认证用户的登录的过滤器
 */
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;
    private RsaKeyProperties prop;

    public JwtLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
        this.authenticationManager = authenticationManager;
        this.prop = prop;
    }

    /**
     * 认证登录用户是否可以通过认证
     */
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        try {
            /**
             * new ObjectMapper()这是jackson提供的一个对象
             * readValue()：读取一个流信息,
             *
             *                  第一个参数是指定流，
             *                  第二个参数是指定要转换的类型
             * request.getInputStream()：获取到请求体中的流信息
             */
            UserInf userEntity = new ObjectMapper().readValue(request.getInputStream(), UserInf.class);
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userEntity.getUsername(), userEntity.getPassword());
            /*将的得到的用户对象提供给spring Security框架自己去验证账号密码是否正确*/
            return authenticationManager.authenticate(authRequest);
        } catch (IOException e) {
            throw new RuntimeException("获取请求体中流信息发生异常：" + e);
        }
    }

    /**
     * 重写这个方法的原因：之前认证通过后是将当前登录用户放入到框架会话对象中
     * SecurityContextHolder.getContext().setAuthentication(authResult);
     * 我们现在前后端分离需要做的就是将存储着用户对象的token返回给前端
     * 认证通过执行的方法
     * 我们需要给请求端返回一条token
     */
    public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult){
        /*下面通过authResult对象的getPrincipal方法可以得到认证通过的对象信息*/
        UserInf user = (UserInf) authResult.getPrincipal();
        /*得到一条token*/
        String token = JwtUtil.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60);
        /*将token写入响应头*/
        response.addHeader("Authorization", "Basic " + token);
        /*设置前端可访问到的响应Key值,多个key值以Authorization区分*/
        response.setHeader("Access-Control-Expose-Headers", "Authorization");
        try {
            /*给请求端一点提示*/
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_OK);
            resultMap.put("message", "认证通过");
            /*writeValueAsString将Map对象序列化成字符串类型*/
            out.write(new ObjectMapper().writeValueAsString(resultMap));
            /*强行输出*/
            out.flush();
            /*将流关闭*/
            out.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
